﻿using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using System.ComponentModel;

namespace EasyXaf.MongoDB;

public class MongoEntityCollection<T> : BindingList<T>
    where T : MongoEntity
{
    protected object MasterObject { get; }

    protected IMemberInfo MemberInfo { get; }

    protected IMemberInfo AssociatedMemberInfo { get; }

    public MongoEntityCollection(
        IList<T> list,
        object masterObject,
        IMemberInfo memberInfo = null,
        string associatedMemberName = null)
        : base(list)
    {
        MasterObject = masterObject;
        MemberInfo = memberInfo;

        if (MemberInfo == null && !string.IsNullOrWhiteSpace(associatedMemberName))
        {
            var typeInfo = XafTypesInfo.Instance.FindTypeInfo(typeof(T));
            AssociatedMemberInfo = typeInfo.FindMember(associatedMemberName);
        }

        AssociatedMemberInfo ??= MemberInfo?.AssociatedMemberInfo;
    }

    public MongoEntityCollection(
        IObjectSpace objectSpace,
        object masterObject,
        IMemberInfo memberInfo = null,
        string associatedMemberName = null)
        : this([], masterObject, memberInfo, associatedMemberName)
    {
        var associatedMemberInfo = AssociatedMemberInfo;
        AssociatedMemberInfo = null;

        if (associatedMemberInfo != null)
        {
            var masterObjectKey = objectSpace.GetKeyValue(masterObject);
            var foreignKeyName = associatedMemberInfo.FindAttribute<MongoForeignKeyAttribute>()?.ForeignKeyName;
            if (!string.IsNullOrWhiteSpace(foreignKeyName))
            {
                var criteria = new BinaryOperator(foreignKeyName, masterObjectKey);
                foreach (var obj in objectSpace.GetObjects<T>(criteria))
                {
                    Add(obj);
                }
            }
        }

        AssociatedMemberInfo = associatedMemberInfo;
    }

    protected override void InsertItem(int index, T item)
    {
        if (item != null)
        {
            AssociatedMemberInfo?.SetValue(item, MasterObject);
        }

        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        AssociatedMemberInfo?.SetValue(this[index], null);

        base.RemoveItem(index);
    }

    protected override void SetItem(int index, T item)
    {
        if (item != null)
        {
            AssociatedMemberInfo?.SetValue(item, MasterObject);
        }

        base.SetItem(index, item);
    }
}
